package readcommand

import (
	"bufio"
	"context"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/go-redis/redis/v8"
)

// CommandArgs ...
type CommandArgs struct {
	APIName    string
	ArgsCount  int
	CodeString string
}

// ExtendRedis ...
type ExtendRedis struct {
	Ctx context.Context
	redis.Client
	RedisSha1List map[string]string
}

func readLuaScripts() ([]*CommandArgs, error) {
	// var cmd map[string]string
	pwd, err := os.Getwd()
	if err != nil {
		return nil, err
	}
	filePath := path.Join(pwd, "../commands")
	fileinfos, err := ioutil.ReadDir(filePath)
	if err != nil {
		return nil, err
	}
	var result []*CommandArgs
	for _, info := range fileinfos {
		if info.IsDir() {
			continue
		}
		fileName := info.Name()
		ext := path.Ext(fileName)
		if ext != ".lua" {
			continue
		}
		commands, err := changeFile(fileName, filePath)
		if err != nil {
			return nil, err
		}
		result = append(result, commands)
	}
	return result, nil
}

func readFile(filePath string) (string, error) {
	f, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer f.Close()
	r := bufio.NewReader(f)
	data := make([]byte, 10)
	var datasting string
	for {
		count, err := r.Read(data)
		if err != nil || err == io.EOF {
			break
		}
		datasting += string(data[:count])
	}
	return datasting, nil
}

func changeFile(fileName string, filePath string) (*CommandArgs, error) {
	fileNameSplits := strings.Split(strings.TrimSuffix(fileName, ".lua"), "-")
	ArgsCount, err := strconv.Atoi(fileNameSplits[1])
	if err != nil {
		return nil, err
	}

	datasting, _ := readFile(path.Join(filePath, fileName))
	return &CommandArgs{
		APIName:    fileNameSplits[0],
		ArgsCount:  ArgsCount,
		CodeString: datasting,
	}, nil
}

// NewExtendRedis ...
func NewExtendRedis(ctx context.Context, c *redis.Client) (*ExtendRedis, error) {
	redisSha1List := make(map[string]string)
	luaScripts, err := readLuaScripts()
	if err != nil {
		return nil, err
	}

	for _, script := range luaScripts {
		cmd := c.ScriptLoad(ctx, script.CodeString)
		redisSha1 := cmd.Val()
		redisSha1List[script.APIName] = redisSha1
	}
	return &ExtendRedis{ctx, *c, redisSha1List}, nil
}

// Run ...
func (exRds *ExtendRedis) Run(APIName string, keys []string, args ...interface{}) *redis.Cmd {
	return exRds.Client.EvalSha(exRds.Ctx, exRds.RedisSha1List[APIName], keys, args...)
}

// ExecScript ...
func (exRds *ExtendRedis) ExecScript(APIName string, lua string, keys []string, args ...interface{}) *redis.Cmd {
	if exRds.RedisSha1List[APIName] == "" {
		cmd := exRds.Client.ScriptLoad(exRds.Ctx, lua)
		redisSha1 := cmd.Val()
		exRds.RedisSha1List[APIName] = redisSha1
	}
	return exRds.Client.EvalSha(exRds.Ctx, exRds.RedisSha1List[APIName], keys, args)
}
